from PyQt4.QtCore import QDir
from PyQt4.QtCore import QDirIterator
from PyQt4.QtCore import QObject
from PyQt4.QtCore import QString
from PyQt4.QtCore import QTime
from PyQt4.QtCore import Qt
from PyQt4.QtCore import SIGNAL
from PyQt4.QtGui import QSizePolicy
from PyQt4.QtGui import QStyle
from PyQt4.QtGui import QSystemTrayIcon
from PyQt4.QtGui import qApp
from PyQt4.phonon import Phonon
import os


'''
MediaManger:
    -read tags
    -play media
    -populate library
'''


class MediaManager(QObject):
    def __init__(self, phonik):
        #parent constructor
        QObject.__init__(self)

        self.phonik = phonik
        self.playList = phonik.playList

        #media objects
        self.audioOutput = Phonon.AudioOutput(Phonon.MusicCategory, phonik)
        self.mediaObject = Phonon.MediaObject(phonik)
        self.metaResolver = Phonon.MediaObject(phonik)        
        self.audioPath = Phonon.createPath(self.mediaObject, self.audioOutput)

        #gui media objects
        self.phonik.seekSlider = Phonon.SeekSlider(self.mediaObject, self.phonik)
        self.phonik.seekSlider.setIconVisible(False)
        self.phonik.controlsLayout.addWidget(self.phonik.seekSlider, 1, 3, 1, 1)

        self.phonik.volumeSlider = Phonon.VolumeSlider(self.audioOutput, self.phonik)
        self.phonik.volumeSlider.setOrientation(Qt.Vertical)
        self.phonik.volumeSlider.setMuteVisible(False)
        self.phonik.volumeSlider.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Preferred)
        self.phonik.controlsLayout.addWidget(self.phonik.volumeSlider, 0, 5, 2, 1)

        #signals
        self.signals()

        self.sources = []
        self.toLibrary = False
        self.working = False
        self.addToPL = False


    def populateLibrary(self, metaData):
        track = metaData[QString('TRACKNUMBER')][0]
        title = metaData[QString('TITLE')][0]
        artist = metaData[QString('ARTIST')][0]
        album = metaData[QString('ALBUM')][0]
        date = metaData[QString('DATE')][0]
        time = metaData[QString('TIME')][0]
        genre = metaData[QString('GENRE')][0]
        file = metaData[QString('URL')][0]

        self.phonik.query.exec_('insert into genres values("' + genre + '")')
        self.phonik.query.exec_('insert into artists values("' + artist + '","' + genre + '")')
        self.phonik.query.exec_('insert into albums values("' + album + '","' + artist + '","' + genre + '")')
        self.phonik.query.exec_('insert into titles values ("' + track + '","' + title + '","' + artist + '","' + album +
                                '","' + date + '","' + time + '","' + genre + '","' + file + '")')


    def addUrls(self, urls, addToPL=False):
        '''adds urls to playlist'''

        self.addToPL = addToPL

        if not addToPL:
            self.playList.clearModel()

        for url in urls:
            if not self.working:
                self.metaResolver.setCurrentSource(Phonon.MediaSource(QString.fromUtf8(url)))
                self.working = True
            else:
                self.sources.append(Phonon.MediaSource(QString.fromUtf8(url)))


    def addDir(self, path, recursively=False, toPlaylist=False, toLibrary=False):

        self.toLibrary = toLibrary
        self.addToPL = toPlaylist

        #do not clear playlist if files are added to library
        if not self.toLibrary and not toPlaylist:
            self.playList.clearModel() 

        if recursively:
            it = QDirIterator(QString.fromUtf8(path), QDir.Files, QDirIterator.Subdirectories)
            while it.hasNext():
                self.parseMedia(it.next())

        else:
            files = os.listdir(path)

            for file in files:
                fullPath = path + os.sep + file
                
                if not os.path.isdir(fullPath):
                    file = QString.fromUtf8(fullPath)
                    self.parseMedia(file)


    def parseMedia(self, file):
        if not self.working:
            self.working = True
            self.metaResolver.setCurrentSource(Phonon.MediaSource(file))
        else:
            self.sources.append(Phonon.MediaSource(file))

    def clearQueue(self):
        del self.sources[:]


    def metaResolverChanged(self, newState, oldState):

        self.phonik.timeLabel.setText(str(len(self.sources)))
        if self.phonik.actionSelectLibraryRoom.isChecked() and len(self.sources) % 200 == 0:
            self.phonik.libraryRoom.loadLibrary()

        if newState == Phonon.StoppedState:
            metaData = self.metaResolver.metaData()
            
            #XRAY too many conditions
            if self.metaResolver.totalTime() != 0 and self.metaResolver.totalTime() != -1 or self.metaResolver.currentSource().type() == Phonon.MediaSource.Url:

                if self.metaResolver.currentSource().type() == Phonon.MediaSource.Url:
                    metaData[QString('URL')] = [self.metaResolver.currentSource().url().toString()]
                else:
                    metaData[QString('URL')] = [self.metaResolver.currentSource().fileName()]

                self.totalTime = self.convertTime(self.metaResolver.totalTime())
                metaData[QString('TIME')] = [self.totalTime]

                #tracknumebr
                if QString('TRACKNUMBER') not in metaData:
                    metaData[QString('TRACKNUMBER')] = [QString()]

                ###XRAY different implementation in phonon.py-backens
                if QString('TRACK-NUMBER') in metaData:
                    metaData[QString('TRACKNUMBER')] = metaData[QString('TRACK-NUMBER')]
                ###

                if len(metaData[QString('TRACKNUMBER')][0]) == 1:
                    metaData[QString('TRACKNUMBER')][0] = '0' + metaData[QString('TRACKNUMBER')][0]

                #title
                if QString('TITLE') not in metaData or metaData[QString('TITLE')] == [QString('')]:
                    title = str(metaData[QString('URL')][0].toUtf8())
                    metaData[QString('TITLE')] = [QString.fromUtf8(title[title.rfind(os.sep) + 1:])]

                #artist
                if QString('ARTIST') not in metaData or metaData[QString('ARTIST')] == [QString('')]:
                    metaData[QString('ARTIST')] = [QString('unknown')]

                #album
                if QString('ALBUM') not in metaData or metaData[QString('ALBUM')] == [QString('')]:
                    metaData[QString('ALBUM')] = [QString('unknown')]

                #date
                if QString('DATE') not in metaData:
                    metaData[QString('DATE')] = [QString()]

                #time
                if QString('TIME') not in metaData:
                    metaData[QString('TIME')] = [QString()]

                #genre
                if QString('GENRE') not in metaData or metaData[QString('GENRE')] == [QString('')]:
                    metaData[QString('GENRE')] = [QString('unknown')]

                if self.toLibrary:
                    self.populateLibrary(metaData)
                else:
                    self.playList.addRow(metaData)


        if newState == Phonon.ErrorState or newState == Phonon.StoppedState:
            if newState == Phonon.ErrorState:
                print self.metaResolver.errorString ()
            #read next file
            if self.sources:
                self.metaResolver.setCurrentSource(self.sources.pop(0))
            else:
                #set working flag
                self.working = False

                #play first track if we added track to playlist
                if not self.toLibrary or self.addToPL:
                    self.playFirst()

                #update lirary
                elif hasattr(self.phonik, 'libraryRoom'):
                    self.phonik.libraryRoom.loadLibrary()

 
    def convertTime(self, time):
        sec = time / 1000 % 60
        min = time / 60000 % 60
        hour = time / 3600000 % 60
        convertedTime = QTime(hour, min, sec)
        if hour:
            return convertedTime.toString('h:mm:ss')
        else:
            return convertedTime.toString('mm:ss')


    def next(self):
        if self.playList.currentIndex ().row() < self.playList.model().rowCount()-1:
            nextIndex = self.playList.currentIndex ().sibling(self.playList.currentIndex ().row() + 1, 0)
            self.playSelected(nextIndex)
            self.playList.setCurrentIndex (nextIndex)
        elif self.phonik.repeatButton.isChecked() and self.sender() == self.mediaObject:
            self.playFirst()


    def prev(self):
        if self.playList.currentIndex().row() > 0:
            prevIndex = self.playList.currentIndex().sibling(self.playList.currentIndex().row() - 1, 0)
            self.playSelected(prevIndex)
            self.playList.setCurrentIndex (prevIndex)
            


    def playSelected(self, index):
        if index and (qApp.keyboardModifiers () != Qt.ControlModifier and qApp.keyboardModifiers () != Qt.ShiftModifier):
            self.currentUrlString = index.sibling(index.row(), 7).data().toString()
            self.mediaObject.setCurrentSource(Phonon.MediaSource(self.currentUrlString))
            self.mediaObject.play()
            self.phonik.playButton.setChecked(True)
            self.totalTime = index.sibling(index.row(), 5).data().toString()


    def currentUrl(self, onlyFilename=False):
        if hasattr(self, 'currentUrlString'):
            if onlyFilename:
                url = str(self.currentUrlString.toUtf8())
                return url[url.rfind(os.sep) + 1:]
            return str(self.currentUrlString.toUtf8())
        return ''


    def playFirst(self):
        if self.playList.model().rowCount() != 0:
            self.playSelected(self.playList.model().index(0, 0))
            self.playList.model().update()


    def playPause(self):
        if  self.mediaObject.state() == Phonon.PausedState:
            self.mediaObject.play()
            self.phonik.playButton.setChecked(True)
        elif self.mediaObject.state() != Phonon.PlayingState and self.playList.model().rowCount() != 0:
            self.playFirst()
        elif self.mediaObject.state() == Phonon.PlayingState:
            self.mediaObject.pause()
            self.phonik.playButton.setChecked(False)


    def shuffle(self):
        import random

        rows = []
        for i in range(self.playList.model().rowCount(), 0, -1):
            rows.append(self.playList.model().takeRow(i-1))

        self.playList.clearModel()
        random.shuffle(rows)

        for row in rows:
            self.playList.model().appendRow(row)

        self.playFirst()


    def tick(self, time):
        #do not set time while parsing media
        if not self.working:
            self.phonik.timeLabel.setText(self.convertTime(time) + ' / ' + self.totalTime)


    def metaDataChanged(self):
        self.playList.scrollTo(self.playList.currentIndex ())

        metadata = self.mediaObject.metaData()
        title = metadata.get(QString('TITLE'), [QString()])[0]
        artist = metadata.get(QString('ARTIST'), [QString()])[0]
        album = metadata.get(QString('ALBUM'), [QString()])[0]

        if not title:
            title = self.currentUrl(True)
            
        titleLabel = '<style>a { color: black;  text-decoration:none} </style>&nbsp;&nbsp;<font><b><a href="title:' + title + '">' + title  + '</a></b></font>'
        toolTip = '<font size=5 color=#0000ff>' + title + '</font>'
        message = title

        if artist:
            if self.phonik.actionShowArtistName.isChecked():
                titleLabel = titleLabel + '<font>&nbsp;&nbsp;<span style="vertical-align:sub;">' + self.tr('by') + '&nbsp;&nbsp;</font><b><a href="artist:' + artist + '">' + artist  + '</a></b></font>'
            toolTip = toolTip + '<br><font color=#000000>' + self.tr('Artist') + ': </font><font color=#0000ff>' + artist + '</font>'
            message = artist + ' - ' + message

        if album:
            if self.phonik.actionShowAlbumName.isChecked():
                titleLabel = titleLabel + '<font> &nbsp;' + '<span style="vertical-align:sub;">' + self.tr('from') + '&nbsp;&nbsp;</font><b><a href="album:' + album + '">' + album  + '</a></b></font>'
            toolTip = toolTip + '<br><font color=#000000>' + self.tr('Album') + ': </font><font color=#0000ff>' + album + '</font>'

        self.phonik.titleLabel.setText(titleLabel)
        self.phonik.systemTrayIcon.setToolTip(toolTip)

        if message and self.phonik.actionShowNowPlaying.isChecked():
            self.phonik.systemTrayIcon.showMessage(self.tr('Now playing'), message, QSystemTrayIcon.Information, 3000)


    def stateChanged(self, newState, oldState):
        if  newState != Phonon.StoppedState and newState != Phonon.PausedState:
            self.phonik.systemTrayIcon.setIcon(self.phonik.style().standardIcon(QStyle.SP_MediaPlay))
        else:
            self.phonik.systemTrayIcon.setIcon(self.phonik.style().standardIcon(QStyle.SP_MediaStop))


    def signals(self):
        self.connect(self.metaResolver, SIGNAL('stateChanged(Phonon::State, Phonon::State)'), self.metaResolverChanged)
        self.connect(self.playList, SIGNAL('clicked (const QModelIndex&)'), self.playSelected)
        self.connect(self.mediaObject, SIGNAL('finished()'), self.next)
        self.connect(self.mediaObject, SIGNAL('tick(qint64)'), self.tick)
        self.connect(self.mediaObject, SIGNAL('metaDataChanged()'), self.metaDataChanged)
        self.connect(self.mediaObject, SIGNAL('stateChanged(Phonon::State, Phonon::State)'), self.stateChanged)
        self.connect(self.phonik.playButton, SIGNAL('clicked(bool)'), self.playPause)
